var bitcore = require('bitcore-lib');
var bitcoinaddress = require('bitcoin-address');
const { logger } = require('./logger');
const pg = require('../db/db');
// var Insight = require('bitcore-explorers').Insight;
// var insight = new Insight(bitcore.Networks.testnet);
let createHDWallet = () => {

    // var bitcore = require(“bitcore - lib”);
    // var Mnemonic = require(‘bitcore - mnemonic’);
    // var code = new Mnemonic();
    // var input = new Buffer(code.toString());
    // var hash = bitcore.crypto.Hash.sha256(input);
    // var bn = bitcore.crypto.BN.fromBuffer(hash);
    // var pk = new bitcore.PrivateKey(bn);
    // var WIF = pk.toWIF();
    // var address = pk.toAddress();
    // console.log(“Mnemonic : “ + code.toString() + “, WIF key : “ + WIF + “ , private key : “ + pk + “ , Public key : “ + address);

    // var Mnemonic = require('bitcore-mnemonic');
    // var code = new Mnemonic();

    // var code = new Mnemonic('select scout crash enforce riot rival spring whale hollow radar rule sentence');

    // var xpriv1 = code.toHDPrivateKey(); // no passphrase
    // var xpriv2 = code.toHDPrivateKey('my passphrase'); // using a passphrase

    // code.toString(); // 'select scout crash enforce riot rival spring whale hollow radar rule sentence'
    // var bitcore = require('bitcore');
    var HDPrivateKey = bitcore.HDPrivateKey;

    var hdPrivateKey = new HDPrivateKey();
    // var retrieved = new HDPrivateKey(xpriv2);
    var derived = hdPrivateKey.derive("m/44'/1'/0'/0");
    // var derivedByNumber = hdPrivateKey.derive(1).derive(2, true);
    // var derivedByArgument = retrieved.derive();
    // assert(derivedByNumber.xprivkey === derivedByArgument.xprivkey);

    var address = derived.privateKey.toAddress().toString();
    // var address = derivedByArgument.hdPublicKey.toAddress();

    // obtain HDPublicKey
    // var hdPublicKey = hdPrivateKey.hdPublicKey;
    var priKey = hdPrivateKey.toString();
}
// createHDWallet()

/**
 * 
 * @param {transaction} transaction {from：'d3034dfsde3w',to:'3xdes08hs3',amount:20,privatekey:'8dekmeb9243fe'}
 */
let createTransaction = (transaction) => {
    return new Promise((resolve, reject) => {

        const unit = bitcore.Unit;
        // const insight = new explorers.Insight();
        const minerFee = unit.fromMilis(0.128).toSatoshis(); //cost of transaction in satoshis (minerfee)
        const amount = unit.fromMilis(transaction.amount).toSatoshis(); //convert mBTC to Satoshis using bitcore unit

        /**
         * Addresses on the Bitcoin Testnet are generated with a different address version,
         * which results in a different prefix. See List of address prefixes and Testnet for more details. 
         * https://en.bitcoin.it/wiki/List_of_address_prefixes
         */
        let type = bitcoinaddress.get_address_type(transaction.from);
        logger.info('bitcoin address type:==>', type); //testnet address :6F

        // if (!bitcoinaddress.validate(transaction.from,type)) {
        //     return reject('Origin address checksum failed');
        // }
        // if (!bitcoinaddress.validate(transaction.to)) {
        //     return reject('Recipient address checksum failed');
        // }

        getUnspentUtxos(transaction.txid, transaction.from, (error, utxos) => {
            if (error) {
                //any other error
                logger.error('getUnspentUtxos error:==>', error);
                return reject(error);
            } else {

                if (utxos.length == 0) {
                    //if no transactions have happened, there is no balance on the address.
                    logger.info("You don't have enough Satoshis to cover the miner fee.");
                    return reject("You don't have enough Satoshis to cover the miner fee.");
                }

                //get balance
                let balance = unit.fromSatoshis(0).toSatoshis();

                for (var i = 0; i < utxos.length; i++) {
                    balance += unit.fromMilis(parseInt(utxos[i]['satoshis'])).toSatoshis();
                }


                /***************************************************测试代码，有效的数据************************************************ */
                // var script = new bitcore.Script.buildPublicKeyHashOut(transaction.from);
                // var utxo = new bitcore.Transaction.UnspentOutput({
                //     "txid": 'e0ad7e6bd6faa584dd47cf3bea266a114a292251c6e274d7503019f22cac5120',
                //     "vout": 0,
                //     "address": "mjUuwfUadmYGrYRfJoDrYqBLFPrnq88Dgv",
                //     "scriptPubKey": script,
                //     "amount": 49
                // });
                /***************************************************测试代码，有效的数据************************************************ */


                //check whether the balance of the address covers the miner fee
                if ((balance - amount - minerFee) > 0) {

                    //create a new transaction
                    try {
                        let bitcore_transaction = new bitcore.Transaction()
                            .from(utxos)
                            .to(transaction.to, amount)
                            .fee(minerFee)
                            .change(transaction.from)
                            .sign(transaction.privatekey);


                        logger.info('bitcore_transaction toStirng:==>', bitcore_transaction.toString())
                        logger.info('bitcore_transaction toJSON:==>', bitcore_transaction.toJSON())

                        //handle serialization errors
                        if (bitcore_transaction.getSerializationError()) {
                            let error = bitcore_transaction.getSerializationError().message;
                            switch (error) {
                                case 'Some inputs have not been fully signed':
                                    logger.error('Some inputs have not been fully signed');
                                    return reject('Please check your private key');
                                    break;
                                default:
                                    logger.error('Some inputs have not been fully signed');
                                    return reject(error);
                            }
                        }

                        // // broadcast the transaction to the blockchain
                        // insight.broadcast(bitcore_transaction, function (error, body) {
                        //     if (error) {
                        //         reject('Error in broadcast: ' + error);
                        //     } else {
                        //         resolve({
                        //             transactionId: body
                        //         });
                        //     }
                        // });

                        updateIsused(transaction.txid, transaction.from).then((error) => {
                            if (error) {
                                logger.error('update isused filed error:==>', error);
                                return reject(error);
                            } else {
                                logger.info('update isused filed successs.');
                                return resolve({ successs: 0000 });
                            }
                        });

                    } catch (error) {
                        logger.error('build transaction:==>', error);
                        return reject(error);
                    }
                } else {
                    logger.error("You don't have enough Satoshis to cover the miner fee.");
                    return reject("You don't have enough Satoshis to cover the miner fee.");
                }
            }
        });
    });
}
let updateIsused = async (txid, address) => {
    let sql = `update utxos set isused='${txid}' where txid ='${txid}' and addresses='${address}'`;
    return pg.none(sql);
}
let getUnspentUtxos = async (txid, from, callback) => {
    try {
        // TODO
        // get utxos by address and txid
        let data = await pg.any(`select txid,value,n,asm,hex,"reqSigs",type,addresses,isused,sum(cast(value as float ))as total_balance 
        from utxos where txid='${txid}' and addresses='${from}' and isused is null
        group by txid,value,n,asm,hex,"reqSigs",type,addresses,isused`);
        // let arr = [];
        let utxo_arr = [];
        data.forEach(obj => {
            // let utx = {};
            // let scriptPubKey = {};
            // let address = [];
            // utx.txid = obj.txid;
            // utx.value = obj.value;
            // utx.n = obj.n;
            // scriptPubKey.asm = obj.asm;
            // scriptPubKey.hex = obj.hex;
            // scriptPubKey.reqSigs = obj.reqSigs;
            // scriptPubKey.type = obj.type;
            // address[0] = obj.addresses;
            // scriptPubKey.addresses = address;
            // utx.scriptPubKey = scriptPubKey;
            // arr.push(utx);

            let utxo = new bitcore.Transaction.UnspentOutput({
                "txid": obj.txid,
                "vout": parseInt(obj.n),
                "address": obj.addresses,
                "scriptPubKey": new bitcore.Script.buildPublicKeyHashOut(obj.addresses),//"038bbf0d8e3884edfdd86eb10c5a359ebcc163d6bb147d1b0e070e0fbfdd28727b", //private key and address must be the same network to make  
                "amount": obj.value
            })
            utxo_arr.push(utxo);

        });

        // var utxo = new bitcore.Transaction.UnspentOutput({
        //     "txid": arr[0].txid,
        //     "vout": 1,
        //     "address": "mjUuwfUadmYGrYRfJoDrYqBLFPrnq88Dgv",
        //     "scriptPubKey": "038bbf0d8e3884edfdd86eb10c5a359ebcc163d6bb147d1b0e070e0fbfdd28727b", //private key and address must be the same network to make  
        //     "amount": 49
        // });

        // success
        callback(null, utxo_arr);
        logger.info('build utxo:==>', utxo_arr);

    } catch (error) {
        logger.error("getBitTransanctions error===>", error);
        callback(error, []);
    }
}
let obj = {
    txid: 'e0ad7e6bd6faa584dd47cf3bea266a114a292251c6e274d7503019f22cac5120',
    from: 'mjUuwfUadmYGrYRfJoDrYqBLFPrnq88Dgv',//已经由别人转了一部分测试的币  2N7dGt4eoWECAszGLV6CV2UhhGeoG4K9jfn
    to: 'n4oC1WTgrW5hJbMVniUshQL99ydUzk5orm',
    amount: '1',
    privatekey: 'cMdckq1KEvXcDQGHyMS5oJwtpuT2kZiqGujqVe8NSvDeM6CFsR6f',
}
createTransaction(obj);






















